/* * This is part of Geomajas, a GIS framework, http://www.geomajas.org/. * * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium. * * The program is available in open source according to the GNU Affero * General Public License. All contributions in this program are covered * by the Geomajas Contributors License Agreement. For full licensing * details, see LICENSE.txt in the project root. */ package org.geomajas.gwt2.client.service; import java.util.Date; import org.geomajas.geometry.Coordinate; import org.geomajas.geometry.Geometry; import org.geomajas.gwt2.client.map.attribute.GeometryType; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsonUtils; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONBoolean; import com.google.gwt.json.client.JSONException; import com.google.gwt.json.client.JSONNull; import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; /** * Utility class for JSON related functionality. * * @author Pieter De Graef * @author Jan De Moerloose */ public final class JsonService { // Specific date formatter for communication with back-end rest. // TODO provide a way to override this default. private static final DateTimeFormat DEFAULT_DATEFORMAT = DateTimeFormat.getFormat(PredefinedFormat.ISO_8601); private JsonService() { // No public constructors for final classes. } /** * Format the given date to a string. The idea is that this string can be used in a JSON object. * * @param date The date to format. * @return The formatted date-string. */ public static String format(Date date) { return DEFAULT_DATEFORMAT.format(date); } /** * Takes in a trusted JSON String and evals it. * * @param jsonString JSON string that you trust. * @return JavaScriptObject that you can cast to an Overlay Type */ public static JavaScriptObject eval(String jsonString) { return JsonUtils.safeEval(jsonString); } /** * Parse the given JSON string into a {@link JSONObject}. * * @param jsonString The trusted JSON string to parse. * @return The JSON object that results from the parsed string. * @throws JSONException Thrown in case something went wrong during parsing. */ public static JSONValue parse(String jsonString) throws JSONException { if (jsonString == null || "".equals(jsonString)) { return JSONNull.getInstance(); } if (jsonString.charAt(0) == '[') { return new JSONArray(eval(jsonString)); } return new JSONObject(eval(jsonString)); } /** * Get a child JSON object from a parent JSON object. * * @param jsonObject The parent JSON object. * @param key The name of the child object. * @return Returns the child JSON object if it could be found, or null if the value was null. * @throws JSONException In case something went wrong while searching for the child. */ public static JSONObject getChild(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null) { if (value.isObject() != null) { return value.isObject(); } else if (value.isNull() != null) { return null; } throw new JSONException("Child is not a JSONObject, but a: " + value.getClass()); } return null; } /** * Get a child JSON array from a parent JSON object. * * @param jsonObject The parent JSON object. * @param key The name of the child object. * @return Returns the child JSON array if it could be found, or null if the value was null. * @throws JSONException In case something went wrong while searching for the child. */ public static JSONArray getChildArray(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null) { if (value.isArray() != null) { return value.isArray(); } else if (value.isNull() != null) { return null; } throw new JSONException("Child is not a JSONArray, but a: " + value.getClass()); } return null; } /** * Get a string value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object or null. * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static String getStringValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null) { if (value.isString() != null) { return ((JSONString) value).stringValue(); } else { String valueString = value.toString(); if (!"null".equals(valueString)) { if (valueString.charAt(0) == '"') { return valueString.substring(1, valueString.length() - 1); } return valueString; } } } return null; } /** * Get a character value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object or null. * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Character getCharValue(JSONObject jsonObject, String key) throws JSONException { String stringValue = getStringValue(jsonObject, key); if (stringValue != null) { return stringValue.charAt(0); } return null; } /** * Get a date value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object or null. * @throws JSONException Thrown in case the key could not be found in the JSON object, or if the date could not be * parsed correctly. */ public static Date getDateValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isString() != null) { String dateString = getStringValue(jsonObject, key); if (dateString.charAt(0) == '"') { dateString = dateString.substring(1); } if (dateString.endsWith("\"")) { dateString = dateString.substring(0, dateString.length() - 1); } try { return DEFAULT_DATEFORMAT.parse(dateString); } catch (Exception e) { try { long millis = Long.parseLong(dateString); return new Date(millis); } catch (Exception e2) { throw new JSONException("Could not parse the date for key '" + key + "'", e); } } } return null; } /** * Get a geometry value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object or null. * @throws JSONException Thrown in case the key could not be found in the JSON object, or if the date could not be * parsed correctly. */ public static Geometry getGeometryValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isObject() != null) { JSONObject obj = value.isObject(); String type = JsonService.getStringValue(obj, "type"); Geometry geometry = new Geometry(type, 0, 5); JSONArray array = JsonService.getChildArray(obj, "coordinates"); switch (GeometryType.fromValue(type)) { case POINT: parseSimple(GeometryType.POINT, geometry, array); break; case LINESTRING: parseSimple(GeometryType.LINEARRING, geometry, array); break; case MULTILINESTRING: parseCollection(GeometryType.LINESTRING, geometry, array); break; case MULTIPOINT: parseCollection(GeometryType.POINT, geometry, array); break; case MULTIPOLYGON: parseCollection(GeometryType.POLYGON, geometry, array); break; case POLYGON: parseCollection(GeometryType.LINEARRING, geometry, array); break; default: break; } return geometry; } return null; } /** * Get a integer value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object . * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Integer getIntValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isNumber() != null) { double number = ((JSONNumber) value).doubleValue(); return new Integer((int) number); } return null; } /** * Get a double value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object . * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Double getDoubleValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isNumber() != null) { double number = ((JSONNumber) value).doubleValue(); return number; } return null; } /** * Get a long value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object . * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Long getLongValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isNumber() != null) { double number = ((JSONNumber) value).doubleValue(); return new Long((long) number); } return null; } /** * Get a short value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object . * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Short getShortValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); if (value != null && value.isNumber() != null) { double number = ((JSONNumber) value).doubleValue(); return new Short((short) number); } return null; } /** * Add a certain object value to the given JSON object. * * @param jsonObject The JSON object to add the value to. * @param key The key to be used when adding the value. * @param value The value to attach to the key in the JSON object. * @throws JSONException In case something went wrong while adding. */ public static void addToJson(JSONObject jsonObject, String key, Object value) throws JSONException { if (jsonObject == null) { throw new JSONException("Can't add key '" + key + "' to a null object."); } if (key == null) { throw new JSONException("Can't add null key."); } JSONValue jsonValue = null; if (value != null) { if (value instanceof Date) { jsonValue = new JSONString(JsonService.format((Date) value)); } else if (value instanceof JSONValue) { jsonValue = (JSONValue) value; } else { jsonValue = new JSONString(value.toString()); } } jsonObject.put(key, jsonValue); } /** * checks if a certain object value is null. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @throws JSONException In case something went wrong while parsing. */ public static boolean isNullObject(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); boolean isNull = false; if (value == null || value.isNull() != null) { isNull = true; } return isNull; } /** * Get a boolean value from a {@link JSONObject}. * * @param jsonObject The object to get the key value from. * @param key The name of the key to search the value for. * @return Returns the value for the key in the object . * @throws JSONException Thrown in case the key could not be found in the JSON object. */ public static Boolean getBooleanValue(JSONObject jsonObject, String key) throws JSONException { checkArguments(jsonObject, key); JSONValue value = jsonObject.get(key); Boolean result = null; if (value != null && value.isBoolean() != null) { return ((JSONBoolean) value).booleanValue(); } return result; } // ------------------------------------------------------------------------ // Private methods: // ------------------------------------------------------------------------ private static void checkArguments(JSONObject jsonObject, String key) throws JSONException { if (key == null) { throw new IllegalArgumentException("Can't go searching for a null key."); } if (jsonObject == null) { throw new JSONException("Can't search for key '" + key + "' in a null object."); } if (!jsonObject.containsKey(key)) { throw new JSONException("Key '" + key + "' could not be found."); } // Please, proceed... } private static void parseCollection(GeometryType type, Geometry geometry, JSONArray array) { Geometry[] geometries = new Geometry[array.size()]; geometry.setGeometries(geometries); for (int i = 0; i < array.size(); i++) { switch (type) { case POINT: geometries[i] = new Geometry(Geometry.POINT, 0, 5); parseSimple(GeometryType.POINT, geometries[i], array.get(i).isArray()); break; case LINEARRING: geometries[i] = new Geometry(Geometry.LINEAR_RING, 0, 5); parseSimple(GeometryType.LINEARRING, geometries[i], array.get(i).isArray()); break; case LINESTRING: geometries[i] = new Geometry(Geometry.LINE_STRING, 0, 5); parseSimple(GeometryType.LINESTRING, geometries[i], array.get(i).isArray()); break; case POLYGON: geometries[i] = new Geometry(Geometry.POLYGON, 0, 5); parseCollection(GeometryType.LINEARRING, geometries[i], array.get(i).isArray()); break; default: break; } } } private static void parseSimple(GeometryType type, Geometry geometry, JSONArray array) { Coordinate[] coords; switch (type) { case POINT: coords = new Coordinate[1]; coords[0] = new Coordinate(); coords[0].setX(array.get(0).isNumber().doubleValue()); coords[0].setY(array.get(1).isNumber().doubleValue()); geometry.setCoordinates(coords); break; case LINEARRING: case LINESTRING: coords = new Coordinate[array.size()]; for (int i = 0; i < coords.length; i++) { coords[i] = new Coordinate(); coords[i].setX(array.get(i).isArray().get(0).isNumber().doubleValue()); coords[i].setY(array.get(i).isArray().get(1).isNumber().doubleValue()); } geometry.setCoordinates(coords); break; default: break; } } }